using Universal.Infrastructure;
using Universal.Application;
using Universal.Api.Configs;
using Serilog.Context;
using Universal.Application.Contracts.Jwt;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Security.Claims;
using Universal.Api.Middleware;

var builder = WebApplication.CreateBuilder(args);

// 配置Serilog日志系统
SerilogConfig.Configure(builder);

builder.Services.AddHttpContextAccessor();

// 注册控制器服务
builder.Services.AddControllers();

// 配置Jwt
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("Jwt"));

// 配置JWT认证
var jwtSettings = builder.Configuration.GetSection("Jwt").Get<JwtSettings>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
#pragma warning disable CS8602 // 解引用可能出现空引用。
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSettings.Issuer,
            ValidAudience = jwtSettings.Audience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)),
            // 添加Claim类型映射
            NameClaimType = ClaimTypes.Name,
            RoleClaimType = ClaimTypes.Role,
            // 设置时钟偏移为0，确保严格验证过期时间
            ClockSkew = TimeSpan.Zero
        };
#pragma warning restore CS8602 // 解引用可能出现空引用。

        // 配置事件以处理token验证
        options.Events = new JwtBearerEvents
        {
            OnTokenValidated = context =>
            {
                // 确保sub claim被正确映射
                var subClaim = context.Principal?.FindFirst("sub");
                if (subClaim != null)
                {
                    Console.WriteLine($"[JWT] Token验证成功，用户ID: {subClaim.Value}");
                }
                else
                {
                    Console.WriteLine("[JWT] Token验证成功，但没有找到sub claim");
                }

                // 打印所有claims用于调试
                Console.WriteLine("[JWT] 所有Claims:");
#pragma warning disable CS8602 // 解引用可能出现空引用。
                foreach (var claim in context.Principal.Claims)
                {
                    Console.WriteLine($"  - {claim.Type}: {claim.Value}");
                }
#pragma warning restore CS8602 // 解引用可能出现空引用。

                Console.WriteLine($"[JWT] Token验证成功，过期时间: {context.SecurityToken.ValidTo:yyyy-MM-dd HH:mm:ss} UTC");
                Console.WriteLine($"[JWT] 当前时间: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");

                return Task.CompletedTask;
            },
            OnAuthenticationFailed = context =>
            {
                Console.WriteLine($"[JWT] 认证失败: {context.Exception.Message}");
                Console.WriteLine($"[JWT] 认证失败类型: {context.Exception.GetType().Name}");
                return Task.CompletedTask;
            }
        };
    });

// 配置授权
builder.Services.AddAuthorization();

// 注册基础设施服务
builder.Services.AddInfrastructure(builder.Configuration);

// 注册应用服务
builder.Services.AddApplication(builder.Configuration);

var app = builder.Build();

// 确保uploads目录存在
var uploadsDir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");
if (!Directory.Exists(uploadsDir))
{
    Directory.CreateDirectory(uploadsDir);
}

// 配置静态文件
app.UseStaticFiles();

// 添加认证和授权中间件
app.UseAuthentication();
app.UseAuthorization();

// 添加权限中间件
app.UsePermissionMiddleware();

// 日志上下文注入 - 在认证之后
app.Use(async (context, next) =>
{
    Guid? userId = null;
    if (context.User.Identity?.IsAuthenticated == true)
    {
        var sub = context.User.FindFirst("sub")?.Value;
        if (Guid.TryParse(sub, out var uid))
            userId = uid;
    }
    var ipAddress = context.Connection.RemoteIpAddress?.ToString();
    LogContext.PushProperty("IpAddress", ipAddress);
    LogContext.PushProperty("UserId", userId);
    var userAgent = context.Request.Headers["User-Agent"].ToString();
    LogContext.PushProperty("UserAgent", userAgent);

    await next();
});

// 配置中间件
app.MapControllers();

app.Run();